import java.util.*;

interface Function {
    Object run(List<Object> args,CacheFuncUtil util);
}


interface Cache{
    Object get(Object args);
    void put(Object args,Object res);
}


class LRUcache implements Cache{
    private Map<Object,Object> resMark;
    private List<Object> queue;
    private int cacheSize;

    LRUcache(int cSize){
        resMark=new HashMap<>();
        queue=new LinkedList<>();
        cacheSize=cSize;
    }

    @Override
    public Object get(Object args){
        var res = resMark.getOrDefault(args,null);
        if(res!=null){
            queue.remove(args);
            queue.add(args);
        }
        return res;
    }

    @Override
    public void put(Object args,Object res){
        queue.add(args);
        resMark.put(args, res);
        while(queue.size()>cacheSize){
            var delKey=queue.remove(0);
            resMark.remove(delKey);
        }
    }
}

class SizeCache implements Cache{
    private Map<Object,Object> resMark;
    private int cacheSize;

    SizeCache(int cSize){
        resMark=new HashMap<>();
        cacheSize=cSize;
    }

    @Override
    public Object get(Object args) {
        return resMark.getOrDefault(args,null);
    }

    @Override
    public void put(Object args, Object res) {
        if(resMark.size()>cacheSize){
            resMark.clear();
        }
        resMark.put(args, res);
    }
}


class CacheFuncUtil {

    private Cache cache;

    private Function runFunc;

    CacheFuncUtil(Cache usedCache,Function function){
        cache=usedCache;
        runFunc=function;
    }

    Object runCacheFunc(List<Object> args){
        Object res=cache.get(args);
        if(res==null){
            res=runFunc.run(args,this);
            cache.put(args,res);
        }
        return res;
    }
}

class CacheRunImpl implements Function{
    @Override
    public Object run(List<Object> args,CacheFuncUtil cacheUtil) {
        List<Integer> stones=(List<Integer>) args.get(0);
        int tmpInd=(Integer) args.get(1);
        int lastStep=(Integer) args.get(2);
        if(tmpInd==stones.size()-1){
            return true;
        }
        int tmpNum=stones.get(tmpInd);
        for (int i = 0; i < 3; i++) {
            int sub=i-1;
            int tmpStep=lastStep+sub;
            if(tmpStep==0){
                continue;
            }
            int searchRes=Collections.binarySearch(stones,tmpNum+tmpStep);
            if(searchRes>=0){
                if((Boolean) cacheUtil.runCacheFunc(Arrays.asList(stones,searchRes,tmpStep))) {
                    return true;
                }
            }
        }
        return false;
    }
}

public class Solution403 {

    public boolean canCross(int[] stones) {
        if(stones.length==2){
            if(stones[1]-stones[0]>1){
                return false;
            }
        }
        CacheRunImpl cacheRun=new CacheRunImpl();
        CacheFuncUtil util=null;
        util = new CacheFuncUtil(new SizeCache(Integer.MAX_VALUE), cacheRun);
        List<Integer> asList=new ArrayList<>();
        for (int i = 0; i < stones.length; i++) {
            asList.add(stones[i]);
        }
        return (Boolean) util.runCacheFunc(Arrays.asList(asList,1,1));
    }
}
